/**
 * 管理员认证控制器
 * 处理管理员登录、登出等认证相关业务逻辑
 */

const bcrypt = require('bcryptjs');
const jwt = require('../../utils/jwt');
const logger = require('../../logger');
const AdminUser = require('../models/adminUser.model');

// 调试模式：使用内存存储的管理员用户（当MongoDB不可用时）
const DEBUG_MODE = process.env.NODE_ENV !== 'production'; // 非生产环境启用调试模式
const DEBUG_ADMIN_USERS = [
    { 
        id: 'debug-admin-1', 
        username: 'admin', 
        password: 'admin123', // 与登录页面显示的默认密码保持一致
        role: 'admin'
    }
];

// 登录尝试限制配置
const LOGIN_ATTEMPTS_LIMIT = 5; // 最大尝试次数
const LOGIN_ATTEMPTS_WINDOW = 15 * 60 * 1000; // 15分钟窗口
const loginAttempts = {}; // 简单的内存存储，生产环境应使用Redis

class AuthController {
    /**
     * 管理员登录
     * @param {Object} req - Express请求对象
     * @param {Object} res - Express响应对象
     */
    async login(req, res) {
        try {
            const { username, password } = req.body;
            
            // 验证输入
            if (!username || !password) {
                return res.status(400).json({
                    error: 'ValidationError',
                    message: '用户名和密码不能为空'
                });
            }
            
            let admin;
            
            // 优先使用调试模式（开发环境）
            if (DEBUG_MODE) {
                // 调试模式：使用内存中的管理员用户
                logger.info('使用调试模式进行管理员登录验证');
                admin = DEBUG_ADMIN_USERS.find(user => user.username === username);
                
                if (!admin) {
                    logger.warn(`调试模式 - 登录尝试失败: 用户名不存在 ${username}`);
                    return res.status(401).json({
                        error: 'Unauthorized',
                        message: '用户名或密码错误'
                    });
                }
                
                // 检查登录尝试次数限制
                if (checkLoginAttemptsLimit(username, res)) {
                    return;
                }
                
                // 调试模式下直接比较明文密码（仅开发环境）
                const isPasswordValid = password === admin.password;
                
                if (!isPasswordValid) {
                    incrementLoginAttempts(username);
                    logger.warn(`调试模式 - 登录尝试失败: 密码错误 用户名=${username}`);
                    return res.status(401).json({
                        error: 'Unauthorized',
                        message: '用户名或密码错误'
                    });
                }
                
                // 登录成功，重置尝试次数
                resetLoginAttempts(username);
                
                // 模拟最后登录时间
                admin.lastLogin = new Date();
                
                logger.info(`调试模式管理员登录验证完成，使用内存用户: ${username}`);
            } else {
                // 正常模式：使用MongoDB
                try {
                    // 查找管理员用户
                    admin = await AdminUser.findOne({ username });
                    
                    if (!admin) {
                        logger.warn(`登录尝试失败: 用户名不存在 ${username}`);
                        return res.status(401).json({
                            error: 'Unauthorized',
                            message: '用户名或密码错误'
                        });
                    }
                    
                    // 检查登录尝试次数限制
                    if (checkLoginAttemptsLimit(username, res)) {
                        return;
                    }
                    
                    // 验证密码
                    const isPasswordValid = await admin.validatePassword(password);
                    
                    if (!isPasswordValid) {
                        incrementLoginAttempts(username);
                        logger.warn(`登录尝试失败: 密码错误 用户名=${username}`);
                        return res.status(401).json({
                            error: 'Unauthorized',
                            message: '用户名或密码错误'
                        });
                    }
                    
                    // 登录成功，重置尝试次数
                    resetLoginAttempts(username);
                    
                    // 更新管理员最后登录时间
                    admin.lastLogin = new Date();
                    await admin.save();
                } catch (dbError) {
                    // 数据库操作失败，在生产环境下记录错误并返回通用错误信息
                    logger.error('管理员登录时数据库操作失败', { error: dbError.message });
                    return res.status(500).json({
                        error: 'DatabaseError',
                        message: '登录过程中发生数据库错误'
                    });
                }
            }
            
            // 生成JWT token和刷新令牌
            const token = jwt.generateToken({
                id: admin.id,
                username: admin.username,
                role: admin.role,
                isAdmin: true
            });
            
            // 生成刷新令牌 (在调试模式下也生成模拟的刷新令牌)
            const refreshToken = jwt.generateRefreshToken({
                id: admin.id,
                username: admin.username
            });
            
            logger.info(`管理员登录成功: ${username}${DEBUG_MODE ? ' (调试模式)' : ''}`);
            
            // 保持与前端期望的响应格式一致
            res.status(200).json({
                token,
                refreshToken,
                user: {
                    id: admin.id,
                    username: admin.username,
                    role: admin.role,
                    lastLogin: admin.lastLogin
                },
                debugMode: DEBUG_MODE
            });
        } catch (error) {
            // 在调试模式下提供更详细的错误信息
            const errorMessage = DEBUG_MODE 
                ? `登录过程中发生错误: ${error.message}`
                : '登录过程中发生错误';
            
            logger.error('登录过程中发生错误', { 
                error: error.message, 
                stack: error.stack,
                debugMode: DEBUG_MODE
            });
            
            console.error('登录错误详情:', error);
            
            res.status(500).json({
                error: 'InternalServerError',
                message: errorMessage,
                debugInfo: DEBUG_MODE ? { stack: error.stack } : undefined
            });
        }
    }
    
    /**
     * 管理员登出
     * @param {Object} req - Express请求对象
     * @param {Object} res - Express响应对象
     */
    async logout(req, res) {
        try {
            // 在实际应用中，这里可以将token加入黑名单
            // 暂时只返回成功信息
            logger.info('管理员登出成功');
            res.status(200).json({
                message: '登出成功'
            });
        } catch (error) {
            logger.error(`管理员登出失败: ${error.message}`);
            res.status(500).json({
                error: 'InternalServerError',
                message: '登出过程中发生错误'
            });
        }
    }
    
    /**
     * 刷新认证令牌
     * @param {Object} req - Express请求对象
     * @param {Object} res - Express响应对象
     */
    async refreshToken(req, res) {
        try {
            const { refreshToken } = req.body;
            
            // 验证刷新令牌是否存在
            if (!refreshToken) {
                logger.warn('刷新令牌请求缺少刷新令牌');
                return res.status(400).json({
                    error: 'BadRequest',
                    message: '刷新令牌不能为空'
                });
            }
            
            // 验证刷新令牌
            const decoded = jwt.verifyRefreshToken(refreshToken);
            
            if (!decoded) {
                logger.warn('无效的刷新令牌');
                return res.status(401).json({
                    error: 'Unauthorized',
                    message: '无效的刷新令牌'
                });
            }
            
            // 在调试模式下，验证管理员用户是否存在
            if (DEBUG_MODE) {
                const admin = DEBUG_ADMIN_USERS.find(user => user.id === decoded.id);
                if (!admin) {
                    logger.warn(`调试模式 - 刷新令牌失败: 管理员不存在 ${decoded.id}`);
                    return res.status(401).json({
                        error: 'Unauthorized',
                        message: '无效的刷新令牌'
                    });
                }
            }
            
            // 生成新的访问令牌
            const newToken = jwt.generateToken({
                id: decoded.id,
                username: decoded.username,
                role: decoded.role || 'admin',
                isAdmin: true
            });
            
            // 生成新的刷新令牌
            const newRefreshToken = jwt.generateRefreshToken({
                id: decoded.id,
                username: decoded.username
            });
            
            logger.info(`管理员令牌刷新成功: ${decoded.username}${DEBUG_MODE ? ' (调试模式)' : ''}`);
            
            res.status(200).json({
                token: newToken,
                refreshToken: newRefreshToken
            });
        } catch (error) {
            logger.error(`刷新令牌请求处理失败: ${error.message}`);
            
            // 区分不同类型的错误
            if (error.name === 'TokenExpiredError') {
                return res.status(401).json({
                    error: 'TokenExpired',
                    message: '刷新令牌已过期，请重新登录'
                });
            }
            
            res.status(500).json({
                error: 'InternalServerError',
                message: DEBUG_MODE ? error.message : '处理刷新令牌请求时发生错误'
            });
        }
    }
}

/**
 * 检查登录尝试次数限制
 * @param {string} username - 用户名
 * @param {Object} res - Express响应对象
 * @returns {boolean} - 如果超过限制返回true
 */
function checkLoginAttemptsLimit(username, res) {
    const attempts = loginAttempts[username] || { count: 0, lastAttempt: 0 };
    const now = Date.now();
    
    // 重置过期的尝试记录
    if (now - attempts.lastAttempt > LOGIN_ATTEMPTS_WINDOW) {
        loginAttempts[username] = { count: 0, lastAttempt: now };
        return false;
    }
    
    if (attempts.count >= LOGIN_ATTEMPTS_LIMIT) {
        const remainingTime = Math.ceil((attempts.lastAttempt + LOGIN_ATTEMPTS_WINDOW - now) / 60000);
        logger.warn(`登录尝试次数过多: ${username}, 剩余锁定时间: ${remainingTime}分钟`);
        res.status(429).json({
            error: 'TooManyRequests',
            message: `登录尝试次数过多，请在${remainingTime}分钟后再试`
        });
        return true;
    }
    
    return false;
}

/**
 * 增加登录尝试次数
 * @param {string} username - 用户名
 */
function incrementLoginAttempts(username) {
    if (!loginAttempts[username]) {
        loginAttempts[username] = { count: 0, lastAttempt: Date.now() };
    }
    loginAttempts[username].count++;
    loginAttempts[username].lastAttempt = Date.now();
}

/**
 * 重置登录尝试次数
 * @param {string} username - 用户名
 */
function resetLoginAttempts(username) {
    delete loginAttempts[username];
}

module.exports = new AuthController();